package com.hugui.stock.service;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.hugui.stock.entity.StockDict;
import com.hugui.stock.entity.StockKline;
import com.hugui.stock.entity.StockMarket;
import com.hugui.stock.service.IStockDictService;
import com.hugui.stock.service.IStockKlineService;
import com.hugui.stock.service.IStockMarketService;
import com.hugui.stock.util.StockDataFileUtil;
import org.springframework.util.CollectionUtils;

/**
 * 并发股票数据收集服务
 */
@Service
public class ConcurrentStockDataService {
    
    private static final Logger logger = LoggerFactory.getLogger(ConcurrentStockDataService.class);
    
    @Autowired
    private IStockDictService stockDictService;
    
    @Autowired
    private IStockMarketService stockMarketService;
    
    @Autowired
    private IStockKlineService stockKlineService;
    
    @Autowired
    private StockApiService stockApiService;
    
    private static final int THREAD_POOL_SIZE = 200;
    private static final int BATCH_SIZE = 200;
    
    /**
     * 并发收集股票数据并保存到本地文件
     */
    public void collectStockDataConcurrently(String stockCode) {
        logger.info("开始并发收集股票数据，股票代码: {}", stockCode);
        
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String currentDate = df.format(new Date());

        // 获取股票列表
        List<StockDict> stockDictList = getStockList(stockCode);
        if (stockDictList.isEmpty()) {
            logger.warn("没有找到需要收集的股票数据");
            return;
        }
        
        logger.info("共找到{}只股票需要收集数据", stockDictList.size());
        
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        
        try {
            // 分批处理股票
            for (int i = 0; i < stockDictList.size(); i += BATCH_SIZE) {
                int endIndex = Math.min(i + BATCH_SIZE, stockDictList.size());
                List<StockDict> batch = stockDictList.subList(i, endIndex);
                
                logger.info("开始处理第{}批股票，共{}只", (i / BATCH_SIZE + 1), batch.size());
                
                // 并发收集数据
                List<CompletableFuture<Boolean>> futures = batch.stream()
                        .map(stock -> CompletableFuture.supplyAsync(() ->
                                collectSingleStockData(stock, currentDate), executor))
                        .collect(Collectors.toList());
                
                // 等待当前批次完成
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
                
                // 检查结果
                long successCount = futures.stream().mapToLong(future -> {
                    try {
                        return future.get() ? 1 : 0;
                    } catch (Exception e) {
                        logger.error("获取股票数据结果失败", e);
                        return 0;
                    }
                }).sum();
                
                logger.info("第{}批股票处理完成，成功: {}/{}", (i / BATCH_SIZE + 1), successCount, batch.size());
                
                // 批次间休息
                if (endIndex < stockDictList.size()) {
                    Thread.sleep(2000);
                }
            }
            
            logger.info("所有股票数据收集完成，开始分析数据...");
        } catch (Exception e) {
            logger.error("并发收集股票数据失败", e);
        } finally {
            executor.shutdown();
            try {
                if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
    
    /**
     * 获取股票列表
     */
    private List<StockDict> getStockList(String stockCode) {
        if ("0".equals(stockCode)) {
            return stockDictService.selectList(null);
        } else {
            StockDict stock = stockDictService.selectOne(
                new EntityWrapper<StockDict>().eq("code", stockCode));
            return stock != null ? Arrays.asList(stock) : null;
        }
    }
    
    /**
     * 收集单个股票数据
     */
    private boolean collectSingleStockData(StockDict stock, String currentDate) {
        try {
            logger.debug("开始收集股票{}数据", stock.getCode());
            
            // 获取股票数据
            List<StockMarket> stockMarketList = stockApiService.getKlineData(
                stock.getCode(), stock.getBase(), "", currentDate, "30");
            
            if (stockMarketList.isEmpty()) {
                logger.warn("股票{}数据获取失败", stock.getCode());
                return false;
            }
            
            // 保存到本地文件
            boolean saved = StockDataFileUtil.saveStockDataToFile(stock.getCode(), stockMarketList);
            
            if (saved) {
                logger.debug("股票{}数据保存成功，共{}条记录", stock.getCode(), stockMarketList.size());
            }
            
            return saved;
            
        } catch (Exception e) {
            logger.error("收集股票{}数据失败: {}", stock.getCode(), e.getMessage(), e);
            return false;
        }
    }
    
    /**
     * 分析数据并保存到数据库
     */
    public void analyzeAndSaveToDatabase() {
        logger.info("开始分析股票数据并保存到数据库...");
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String currentDate = df.format(new Date());

                // 获取股票列表
        List<StockDict> stockDictList = getStockList("0");
        int successCount = 0;
        assert stockDictList != null;
        int totalCount = stockDictList.size();

        StringBuilder sb = new StringBuilder();
        for (StockDict stock : stockDictList) {
            try {
                // 从文件加载数据
                List<StockMarket> stockMarketList = StockDataFileUtil.loadStockDataFromFile(stock.getCode());
                
                if (stockMarketList == null || stockMarketList.isEmpty()) {
                    logger.warn("股票{}数据文件不存在或为空", stock.getCode());
                    sb.append(stock.getCode()).append(",");
                    continue;
                }
                
                // 查找当天数据
                StockMarket todayData = findTodayData(stockMarketList, currentDate);
                if (todayData == null) {
                    logger.warn("股票{}没有当天交易数据", stock.getCode());
                    continue;
                }
                
                // 计算均线数据
                StockKline klineData = stockApiService.calculateKlineData(stockMarketList);
                if (klineData == null) {
                   logger.warn("股票{}均线数据计算失败", stock.getCode());
                    continue;
                }
                
                // 保存到数据库
                stockMarketService.insert(todayData);
                stockKlineService.insert(klineData);
                
                successCount++;
                logger.debug("股票{}数据保存到数据库成功", stock.getCode());
                
            } catch (Exception e) {
                logger.error("处理股票{}数据失败: {}", stock.getCode(), e.getMessage(), e);
            }
        }

        System.out.println(sb.toString());
        logger.info("数据库保存完成，成功: {}/{}", successCount, totalCount);
    }
    
    /**
     * 查找当天交易数据
     */
    private StockMarket findTodayData(List<StockMarket> stockMarketList, String currentDate) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        
        for (StockMarket marketData : stockMarketList) {
            if (currentDate.equals(df.format(marketData.getTradingDate()))) {
                return marketData;
            }
        }
        
        return null;
    }
} 